/**
*****************************************************************************************
*     Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved.
*****************************************************************************************
   * @file      app_task.c
   * @brief     Routines to create App task and handle events & messages
   * @author    jane
   * @date      2017-06-02
   * @version   v1.0
   **************************************************************************************
   * @attention
   * <h2><center>&copy; COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2>
   **************************************************************************************
  */

/*============================================================================*
 *                              Header Files
 *============================================================================*/
#include <os_msg.h>
#include <os_task.h>
#include <gap.h>
#include <gap_le.h>
#include <app_msg.h>
#include <app_task.h>
#include <peripheral_app.h>
#include <string.h>

#include "rtl876x_gpio.h"
#include "rtl876x_pinmux.h"
#include "rtk_common.h"
#include "rtk_uart.h"

#include "mi_config.h"
#include "mible_api.h"
#include "mible_log.h"

#include "common/mible_beacon_internal.h"
#include "common/mible_beacon.h"
#include "secure_auth/mible_secure_auth.h"
#include "mijia_profiles/mi_service_server.h"
#include "mijia_profiles/stdio_service_server.h"
#include "mijia_profiles/lock_service_server.h"

#include "data_uart.h"
#include "ftl.h"
#include "app_main.h"
#include "mijia_uart.h"
#include "mible_mcu.h"
#include "miio_user_api.h"

#if MI_MANU_TEST_ENABLE
#include "mijia_mp_cmd.h"
#include "mijia_mp_cmd_parser.h"
#endif
#if MI_USER_CMD_ENABLE
#include "mi_cmd.h"
#endif

/** @defgroup  PERIPH_APP_TASK Peripheral App Task
    * @brief This file handles the implementation of application task related functions.
    *
    * Create App task and handle events & messages
    * @{
    */
/*============================================================================*
 *                              Macros
 *============================================================================*/
#define APP_TASK_PRIORITY             1         //!< Task priorities
#define APP_TASK_STACK_SIZE           (1024*8)    //!<  Task stack size
#define MAX_NUMBER_OF_GAP_MESSAGE     32      //!<  GAP message queue size
#define MAX_NUMBER_OF_IO_MESSAGE      32      //!<  IO message queue size
#define MI_TASK_QUEUE_SIZE            2
#define MAX_NUMBER_OF_EVENT_MESSAGE   (MAX_NUMBER_OF_GAP_MESSAGE + MAX_NUMBER_OF_IO_MESSAGE + MI_TASK_QUEUE_SIZE + MIBLE_API_MSG_NUM + MI_UART_MSG_NUM)    //!< Event message queue size

#define EVENT_MI_TASK                 0x81
#define EVENT_MI_BLEAPI               0x82
#define EVENT_MI_UART                 0x83

typedef struct
{
    mible_handler_t handler;
    void *arg;
} mi_event_t;

/*============================================================================*
 *                              Variables
 *============================================================================*/
static void *app_task_handle;   //!< APP Task handle
static void *evt_queue_handle;  //!< Event queue handle
static void *io_queue_handle;   //!< IO queue handle
//static void *mi_queue_handle;   // mi auth
#if MI_MANU_TEST_ENABLE || MI_USER_CMD_ENABLE || OOB_USE_NUMPAD_INPUT
static void *mi_uart_queue_handle;   //!< IO queue handle
#endif
extern bool need_kbd_input;

/*============================================================================*
 *                              Functions
 *============================================================================*/
void app_main_task(void *p_param);

extern mible_status_t mible_record_init(void);
//extern void user_record_init(void);

/**
 * @brief  Initialize App task
 * @return void
 */
void app_task_init()
{
    os_task_create(&app_task_handle, "app", app_main_task, 0, APP_TASK_STACK_SIZE,
                   APP_TASK_PRIORITY);
}

bool app_send_msg_to_apptask(T_IO_MSG *p_msg)
{
    uint8_t event = EVENT_IO_TO_APP;

    if (os_msg_send(io_queue_handle, p_msg, 0) == false)
    {
        APP_PRINT_ERROR0("send_io_msg_to_app fail");
        return false;
    }
    if (os_msg_send(evt_queue_handle, &event, 0) == false)
    {
        APP_PRINT_ERROR0("send_evt_msg_to_app fail");
        return false;
    }
    return true;
}

void app_handle_uart_msg(uint8_t *pdata, uint16_t len)
{
#if 0//OOB_USE_NUMPAD_INPUT
    if(need_kbd_input){
        need_kbd_input = false;
        mi_schd_oob_rsp(pdata, 6);
        MI_LOG_INFO("OOB Input: %02x%02x%02x%02x%02x%02x\n", 
            pdata[0], pdata[1], pdata[2], pdata[3], pdata[4], pdata[5]);
        return;
    }
#endif
    
#if MI_MANU_TEST_ENABLE
    mijia_mp_cmd_parse(pdata, len);
#endif

#if MI_USER_CMD_ENABLE
    user_cmd_collect(pdata, len, mi_cmd_table);
#endif
}



/**
 * @brief output system information
 */
#include "patch_header_check.h"
void app_system_info(void)
{
    T_IMG_ID image_id;
    T_IMAGE_VERSION image_version;
    const char *name = NULL;
    uint8_t mac[6] = {0};
    uint32_t device_id[2] = {0};

    DBG_DIRECT(" ");
    DBG_DIRECT("_|      _|  _|_|_|  _|_|_|    _|_|  ");
    DBG_DIRECT("_|_|  _|_|    _|      _|    _|    _|");
    DBG_DIRECT("_|  _|  _|    _|      _|    _|    _|");
    DBG_DIRECT("_|      _|    _|      _|    _|    _|");
    DBG_DIRECT("_|      _|  _|_|_|  _|_|_|    _|_|  ");
    DBG_DIRECT(" ");

    for (image_id = OTA; image_id < IMAGE_MAX; ++image_id)
    {
        switch (image_id)
        {
        case OTA:
            name = "OTA header";
            break;
        case SecureBoot:
            name = "Secure boot";
            break;
        case RomPatch:
            name = "ROM patch";
            break;
        case AppPatch:
            name = "SDK";
            break;
        case AppData2:
            name = "Patch extention";
            break;
        default:
            name = NULL;
            break;
        }

        if (NULL == name)
        {
            continue;
        }

        if (get_active_bank_image_version(image_id, &image_version))
        {
            if (OTA == image_id)
            {
                DBG_DIRECT("%s version: %d.%d.%d.%d", name,
                           image_version.ver_info.header_sub_version._version_major,
                           image_version.ver_info.header_sub_version._version_minor,
                           image_version.ver_info.header_sub_version._version_revision,
                           image_version.ver_info.header_sub_version._version_reserve);
            }
            else
            {
                DBG_DIRECT("%s version: %d.%d.%d.%d", name,
                           image_version.ver_info.img_sub_version._version_major,
                           image_version.ver_info.img_sub_version._version_minor,
                           image_version.ver_info.img_sub_version._version_revision,
                           image_version.ver_info.img_sub_version._version_reserve);
            }

        }
        else
        {
            DBG_DIRECT("Fail to get %s version !!!", name);
        }
    }

    DBG_DIRECT(" ");
    DBG_DIRECT("Product ID: %d", PRODUCT_ID);
    DBG_DIRECT("Model: %s", MODEL_NAME);
    extern void get_device_id(uint8_t *pdid);
    get_device_id((uint8_t *)device_id);
    if (0 == device_id[1])
    {
        DBG_DIRECT("Device ID: %u", device_id[0]);
    }
    else
    {
        DBG_DIRECT("Device ID: 0x%08X%08X", device_id[1], device_id[0]);
    }
    if (GAP_CAUSE_SUCCESS == gap_get_param(GAP_PARAM_BD_ADDR, mac))
    {
        DBG_DIRECT("MAC address: %02X %02X %02X %02X %02X %02X",
                   mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
    }
    else
    {
        DBG_DIRECT("Fail to get MAC address !!!");
    }
    DBG_DIRECT("Firmware version: " MIBLE_LIB_AND_DEVELOPER_VERSION);
    DBG_DIRECT(" ");
}




/**
 * @brief        App task to handle events & messages
 * @param[in]    p_param    Parameters sending to the task
 * @return       void
 */
void app_main_task(void *p_param)
{
    uint8_t event;

    MI_LOG_INFO("Compiled %s %s\n", __DATE__, __TIME__);

    os_msg_queue_create(&evt_queue_handle, MAX_NUMBER_OF_EVENT_MESSAGE, sizeof(uint8_t));
    os_msg_queue_create(&io_queue_handle, MAX_NUMBER_OF_IO_MESSAGE, sizeof(T_IO_MSG));
    //os_msg_queue_create(&mi_queue_handle, MI_TASK_QUEUE_SIZE, sizeof(mi_event_t));

    gap_start_bt_stack(evt_queue_handle, io_queue_handle, MAX_NUMBER_OF_GAP_MESSAGE);
    mible_api_init(EVENT_MI_BLEAPI, evt_queue_handle);
    mi_task_start(EVENT_MI_TASK, evt_queue_handle);

    /* Add mijia auth code */
    mible_record_init();
//    user_record_init();

#if MI_MANU_TEST_ENABLE || MI_USER_CMD_ENABLE || OOB_USE_NUMPAD_INPUT
    os_msg_queue_create(&mi_uart_queue_handle, MI_UART_MSG_NUM, sizeof(mijia_uart_msg_t));
    mijia_uart_init(P3_0, P3_1, EVENT_MI_UART, evt_queue_handle, mi_uart_queue_handle);
#endif

#if MI_MANU_TEST_ENABLE
    mijia_mp_cmd_init();
#endif
    
#if MI_USER_CMD_ENABLE
    data_uart_debug_switch(true);
    user_cmd_init("Mijia secure auth");
#endif
    
    app_system_info();

    user_app_init();
    
    while (os_msg_recv(evt_queue_handle, &event, 0xFFFFFFFF))
    {
        switch (event)
        {
        case EVENT_IO_TO_APP:
            {
                T_IO_MSG io_msg;
                if (os_msg_recv(io_queue_handle, &io_msg, 0))
                {
                    app_handle_io_msg(io_msg);
                }
            }
            break;
        case EVENT_MI_BLEAPI:
            {
                mible_api_inner_msg_handle(event);
            }
            break;
        case EVENT_MI_TASK:
            mible_tasks_exec();
            break;
#if MI_MANU_TEST_ENABLE || MI_USER_CMD_ENABLE || OOB_USE_NUMPAD_INPUT
        case EVENT_MI_UART:
            {
                mijia_uart_msg_t uart_msg;
                if (os_msg_recv(mi_uart_queue_handle, &uart_msg, 0) == true)
                {
                    app_handle_uart_msg(uart_msg.data, uart_msg.len);
                }
            }
            break;
#endif
        default:
            gap_handle_msg(event);
        }
        user_app_main_thread();
    }
}

/** @} */ /* End of group PERIPH_APP_TASK */
